#include <QCoreApplication>
#include "tcpserver.h"

const qint64 cmd_sendIpAndHostName = 111;
const qint64 cmd_dataCollectionStart = 222;
const qint64 cmd_dataCollectionStop = 333;
const qint64 cmd_faultDiagnosis = 444;
const qint64 cmd_stopTransmition = 555;
extern QString FileName;

tcpServer::tcpServer():var_bytesHaveRecieve(0),var_fileBytesHaveSent(0),
    var_isSendFilesComplete(true)
{
    var_server = new QTcpServer(this);
    var_udpServer = new udpServer;
    var_udpThread = new QThread(this);
    var_dataCollect = new DataCollect;
    var_dataCollectThread = new QThread(this);
    var_faultDiagnosis = new FaultDiagnosis;
    var_faultDiagnosisThread = new QThread(this);

    var_udpServer->moveToThread(var_udpThread);
    var_dataCollect->moveToThread(var_dataCollectThread);
    var_faultDiagnosis->moveToThread(var_faultDiagnosisThread);

    connect(var_server,&QTcpServer::newConnection,this,&tcpServer::accpetConnection);
    connect(var_server,&QTcpServer::acceptError,this,&tcpServer::errorOccur);
    connect(this,&tcpServer::dataCollectionSignal,var_dataCollect,&DataCollect::dataCollectionControl);
    connect(var_dataCollect,&DataCollect::dataCollectInfo,this,&tcpServer::sendInformation);
    connect(var_dataCollect,&DataCollect::dataCollectFinish,this,&tcpServer::sendDataFiles);
    connect(this,&tcpServer::faultDiagnosisSignal,var_faultDiagnosis,&FaultDiagnosis::faultDiagnosisResults);
    connect(var_faultDiagnosis,&FaultDiagnosis::faultDiagnosisFinished,this,&tcpServer::sendDiagnosisResult);

    var_udpThread->start();
    var_dataCollectThread->start();
    var_faultDiagnosisThread->start();
}

tcpServer::~tcpServer()
{
    var_udpThread->quit();
    var_udpThread->wait();

    var_dataCollectThread->quit();
    var_dataCollectThread->wait();

    var_dataCollectThread->quit();
    var_dataCollectThread->wait();

    var_server->close();

    delete var_udpServer;
    delete var_dataCollect;
    delete var_faultDiagnosis;
}

bool tcpServer::start()
{
    if(var_server->listen(QHostAddress::AnyIPv4,TCP_SERVER_PORT))
    {
        qDebug("listening......");
        return true;
    }
    else
    {
        qDebug("listen failed");
        return false;
    }
}

void tcpServer::sendDataFiles()
{
    var_fileBytesHaveSent = 0;
    var_fileTotalBytes = 0;
    QDataStream out(&var_fileBlock,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_6_9);
    var_file.setFileName(FileName);
    if(var_file.open(QIODevice::ReadOnly))
    {
        QString fileName = var_file.fileName().right(var_file.fileName().size() -
                                                     var_file.fileName().lastIndexOf("/") - 1);
        var_fileTotalBytes = var_file.size();
        out << qint64(0) << qint64(0) << fileName;
        var_fileTotalBytes += var_fileBlock.size();
        out.device()->seek(0);
        //不能直接用fileName.size(), size()只是字符串的大小而不是qstring的大小
        out << var_fileTotalBytes << var_fileBlock.size()-qint64(2*sizeof(qint64));
        var_fileBlock.push_front(qint8(TYPE_FILE)); // 插入数据类型标记
        var_socket->write(var_fileBlock);
        var_fileBytesHaveSent = var_fileBytesHaveSent + var_fileBlock.size() - sizeof(qint8);
        var_fileBlock.resize(0);
        qDebug() << tr("获取var_totalBytes: %1").arg(var_fileTotalBytes);
        qDebug() << tr("获取var_bytesHaveSent: %1").arg(var_fileBytesHaveSent);
    }
    else
    {
        qDebug("open file failed");
        var_file.close();
        return;
    }
}

void tcpServer::sendDiagnosisResult(QString result)
{
    var_dataTotalBytes = 0;
    var_dataBlock.resize(0);
    QDataStream out(&var_dataBlock,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_6_9);
    out << qint64(0) << result;
    out.device()->seek(0);
    var_dataTotalBytes = var_dataBlock.size();
    out << var_dataTotalBytes;
    var_dataBlock.push_front(qint8(TYPE_DATA)); // 插入数据类型标记
    qDebug() << "发送的var_totalBytes: " << var_dataTotalBytes;
    qDebug() << "发送的string: " << result;
    var_socket->write(var_dataBlock);
}

void tcpServer::sendInformation(QString result)
{
    var_dataTotalBytes = 0;
    var_dataBlock.resize(0);
    QDataStream out(&var_dataBlock,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_6_9);
    out << qint64(0) << result;
    out.device()->seek(0);
    var_dataTotalBytes = var_dataBlock.size();
    out << var_dataTotalBytes;
    var_dataBlock.push_front(qint8(TYPE_INFO)); // 插入数据类型标记
    qDebug() << "发送的var_totalBytes: " << var_dataTotalBytes;
    qDebug() << "发送的string: " << result;
    var_socket->write(var_dataBlock);
}

void tcpServer::accpetConnection()
{
    var_socket = var_server->nextPendingConnection();
    var_socket->setReadBufferSize(READ_BUFFER);
    connect(var_socket,&QTcpSocket::readyRead,this,&tcpServer::readyReceive);
    connect(var_socket,&QTcpSocket::bytesWritten,this,&tcpServer::readySend);
    connect(var_socket,&QTcpSocket::disconnected,var_socket,&QTcpSocket::deleteLater);
    connect(var_socket,&QTcpSocket::disconnected,this,[&]{qDebug() << "The Server Socket is closed~";});
    qDebug() << "Client IP: " << var_socket->peerAddress().toString();
}

void tcpServer::errorOccur()
{
    qDebug() << "Server Error: " << var_server->errorString();
}

void tcpServer::readySend(qint64 bytesWritten)
{
    if(!var_isSendFilesComplete)
    {
        // qDebug() << tr("获取bytesWritten: %1").arg(bytesWritten);
        QDataStream out(&var_fileBlock,QIODevice::WriteOnly);
        if(var_fileBytesHaveSent < var_fileTotalBytes)
        {
            out << qint8(TYPE_FILE);
            var_fileBlock.append(var_file.read(WRITE_PAYLOADSIZE));
            var_fileBytesHaveSent = var_fileBytesHaveSent + var_socket->write(var_fileBlock) - sizeof(qint8);
            var_fileBlock.resize(0);
            // qDebug() << tr("获取bytesHaveSent: %1").arg(var_fileBytesHaveSent);
        }
        else if(var_fileBytesHaveSent == var_fileTotalBytes)
        {
            var_file.close();
            var_isSendFilesComplete = true;
            qDebug("send complete");
        }
    }
}

void tcpServer::readyReceive()
{
    QDataStream in(var_socket);
    in.setVersion(QDataStream::Qt_6_9);
    if(var_bytesHaveRecieve == 0)
    {
        if(var_socket->bytesAvailable() < qint64(sizeof(qint8)))
            return;
        in >> var_dataType;
        var_bytesHaveRecieve += sizeof(var_dataType);
    }
    if(var_dataType == TYPE_CMD)
    {
        if(var_socket->bytesAvailable() >= qint64(sizeof(qint64)))
        {
            in >> var_receivedCMD;
            if(var_receivedCMD == cmd_dataCollectionStart)
            {
                emit dataCollectionSignal(cmd_dataCollectionStart);
            }
            else if(var_receivedCMD == cmd_dataCollectionStop)
            {
                emit dataCollectionSignal(cmd_dataCollectionStop);
                var_isSendFilesComplete = false;
            }
            else if(var_receivedCMD == cmd_faultDiagnosis)
            {
                emit faultDiagnosisSignal();
            }
            else if(var_receivedCMD == cmd_stopTransmition)
            {
                var_isSendFilesComplete = true;
                var_socket->abort();
            }
            var_bytesHaveRecieve = 0;
            // qDebug() << "readyReceive() cmd:" << var_receivedCMD;
        }
    }
    else if(var_dataType == TYPE_DATA)
    {

    }
    else if(var_dataType == TYPE_FILE)
    {

    }
}
//-------------------------UDP------------------------------//
udpServer::udpServer(QObject *parent):QUdpSocket(parent)
{
    bind(UDP_SERVER_PORT);
    connect(this,&udpServer::readyRead,this,&udpServer::readPendingDatagrams);
    connect(this,&udpServer::bytesWritten,this,&udpServer::sendPendingDatagrams);
    connect(this,&udpServer::errorOccurred,this,&udpServer::errorOccur);
}

udpServer::~udpServer()
{

}

void udpServer::readIpAndHostName()
{
    QString configFilePath = QCoreApplication::applicationDirPath() + "/config.ini";
    QFileInfo fileInfo(configFilePath);
    if(fileInfo.exists())
    {
        QSettings config(configFilePath,QSettings::IniFormat);
        var_IpAddress = config.value("IPAddress").toString();
        var_HostName = config.value("HostName").toString();
    }
    else
    {
        QSettings config(configFilePath,QSettings::IniFormat);
        QList<QHostAddress>ipList = QNetworkInterface::allAddresses();
        for(auto &ip : ipList)
        {
            if(ip.protocol() == QHostAddress::IPv4Protocol)
            {
                config.setValue("IPAddress",ip.toString());
                config.setValue("HostName",QSysInfo::machineHostName());
                break;
            }
        }
    }
}

void udpServer::readPendingDatagrams()
{
    while(hasPendingDatagrams())
    {
        QNetworkDatagram datagrams = receiveDatagram(pendingDatagramSize());
        if(datagrams.isValid())
        {
            qDebug() << "server udp";
            QByteArray inblock = datagrams.data();
            if(inblock.size() == sizeof(cmd_sendIpAndHostName))
            {
                QDataStream in(&inblock,QIODevice::ReadOnly);
                in.setVersion(QDataStream::Qt_6_9);
                in >> var_receivedCMD;
                if(var_receivedCMD == cmd_sendIpAndHostName)
                {
                    readIpAndHostName();
                    sendDatagrams();
                }
            }
        }
    }
}

void udpServer::sendDatagrams()
{
    QByteArray outblock;
    QDataStream out(&outblock,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_6_9);
    out << var_IpAddress << var_HostName;
    writeDatagram(outblock,QHostAddress::Broadcast,UDP_CLIENT_PORT);
}

void udpServer::sendPendingDatagrams()
{
}

void udpServer::errorOccur()
{
    qDebug() << "UDP Error:" << errorString();
}
